package at.technikum_wien.embsys.aat.PriscillaCore.component;

import java.util.Iterator;
import java.util.List;

import at.technikum_wien.embsys.aat.PriscillaCore.enums.EnoceanComponentType;
import at.technikum_wien.embsys.aat.PriscillaCore.event.FrameEventIllumination;
import at.technikum_wien.embsys.aat.PriscillaCore.event.FrameEventSupplyVoltage;
import at.technikum_wien.embsys.aat.PriscillaCore.link.event.LinkListener;
import at.technikum_wien.embsys.aat.PriscillaCore.telegram.Telegram;



/**
 * 
 * EEP_07_06_01 component class - light sensor
 *
 * Type: light sensor
 * Illumination max: 60000lx
 * Illumination min: 300lx

 * @author B. Aigner
 * 
 */
public class EEP_07_06_01 implements EnoceanComponent {
	
	Telegram telegram;
	List<?> eventListener;
	float illumination = -300F;
	float voltage = -300F;
	EnoceanComponentType enoceanComponentType = EnoceanComponentType.EEP_07_06_01;
	boolean telegramCreation = false;
	
	int illumination_temp;
	float illumination_max;
	float illumination_min;
	int illumination_value_max = 255;
	int illumination_value_min = 0;
	
	int voltage_temp;
	float voltage_max = 5.1F;
	float voltage_min = 0;
	int voltage_value_max = 255;
	int voltage_value_min = 0;
	
	float multiplier;

	/**
	 * This constructor is used for received packets.
	 * It will parse the telegram and set the corresponding members.
	 * 
	 * @param telegram Received Telegram
	 * @param listener Event subscriber list
	 */
	public EEP_07_06_01(Telegram telegram, List<?> listener) {
		super();
		this.telegram = telegram;
		this.eventListener = listener;
	
		if(checkBit(telegram.getData0(),0)) {
			illumination_temp = telegram.getData2();
			illumination_max = 30000;
			illumination_min = 300;
		} else {
			illumination_temp = telegram.getData1();
			illumination_max = 60000;
			illumination_min = 600;
		}

		voltage_temp = telegram.getData3();
		
		multiplier = (illumination_max - illumination_min) / (illumination_value_max - illumination_value_min);
		
		if(multiplier < 0) {
			this.illumination = multiplier * illumination_temp + illumination_max;
		} else {
			this.illumination = multiplier * illumination_temp + illumination_min;
		}
		
		multiplier = (voltage_max - voltage_min) / (voltage_value_max - voltage_value_min);
		
		if(multiplier < 0) {
			this.voltage = multiplier * voltage_temp + voltage_max;
		} else {
			this.voltage = multiplier * voltage_temp + voltage_min;
		}

		fireFrame();
	}

	/**
	 * Fire all associated events
	 */
	void fireFrame() {
		Iterator<?> listen = eventListener.iterator();
		final FrameEventIllumination frameEventIllumination = new FrameEventIllumination(this, telegram.getDeviceID(), this.illumination);
		while (listen.hasNext()) {
			((LinkListener) listen.next()).frameReceived_Illumination(frameEventIllumination);
		}
		
		listen = eventListener.iterator();
		final FrameEventSupplyVoltage frameEventSupplyVoltage = new FrameEventSupplyVoltage(this, telegram.getDeviceID(), this.voltage);
		while (listen.hasNext()) {
			((LinkListener) listen.next()).frameReceived_SupplyVoltage(frameEventSupplyVoltage);
		}
	}

	/**
	 * Void constructor. It is used to create a new telegram for sending
	 */
	public EEP_07_06_01() {
		super();
		telegram = new Telegram();
		telegramCreation = true;
	}

	/**
	 * This constructor is used to create a telegram (the device id is given as parameter)
	 * @param deviceID Full device ID
	 */
	public EEP_07_06_01(String deviceID) {
		super();
		telegram = new Telegram();
		telegram.setDeviceID(deviceID);
		telegramCreation = true;
	}
	
	boolean checkBit(int value, int bitNr) {
		return (value & (1 << bitNr)) != 0;
	}
	@Override
	public String getDeviceID() {
		return telegram.getDeviceID();
	}
	@Override
	public String getORG() {
		return telegram.getxORG();
	}
	@Override
	public EnoceanComponentType getType() {
		return enoceanComponentType;
	}

	@Override
	public void setDeviceID(String deviceID) {
		telegram.setDeviceID(deviceID);
	}
	
	/**
	 * Creates a new telegram from the component
	 * 
	 * This method creates a new telegram (if the component is initialized with
	 * a constructor without a telegram as parameter) or returns the saved telegram.
	 * The new telegram is built up from the members in this class (in this case illumination). 
	 * @return Created telegram
	 */
	public Telegram getTelegram() {
		if(telegramCreation == true) {
			if(illumination > 30000) {
				multiplier = (60000 - 600) / (illumination_value_max - illumination_value_min);
				if(multiplier < 0) {
					telegram.setData1((int)((this.illumination - 60000) / multiplier));
				} else {
					telegram.setData1((int)((this.illumination - 600) / multiplier));
				}
				telegram.setData0(0x08);
			} else {
				multiplier = (30000 - 300) / (illumination_value_max - illumination_value_min);
				if(multiplier < 0) {
					telegram.setData2((int)((this.illumination - 30000) / multiplier));
				} else {
					telegram.setData2((int)((this.illumination - 300) / multiplier));
				}
				telegram.setData0(0x09);
			}
			
			multiplier = (voltage_max - voltage_min) / (voltage_value_max - voltage_value_min);
			if(multiplier < 0) {
				telegram.setData3((int)((this.voltage - voltage_max) / multiplier));
			} else {
				telegram.setData3((int)((this.voltage - voltage_min) / multiplier));
			}	
		}
		return telegram;
	}

	public float getIllumination() {
		return illumination;
	}

	public float getVoltage() {
		return voltage;
	}

	public void setIllumination(float illumination) {
		if(illumination > 60000) return;
		this.illumination = illumination;
	}

	public void setVoltage(float voltage) {
		if(voltage > 5.1F) return;
		this.voltage = voltage;
	}
}
